﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Net;
using System.Xml;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.WebControls;
using Kiiro.Logging;
using Kiiro.ExceptionManagement;
using Kiiro.Common.Utility;
using Kiiro.Common.Entities;
using Kiiro.Model;

namespace Kiiro.WebServices
{
    /// <summary>
    /// 
    /// </summary>
    [WebService ( Namespace = "http://tempuri.org/" )]
    [WebServiceBinding ( ConformsTo = WsiProfiles.BasicProfile1_1 )]
    [System.ComponentModel.ToolboxItem ( false )]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    // [System.Web.Script.Services.ScriptService]
    public class Service : System.Web.Services.WebService
    {
        [WebMethod]
        public int IsProjectManager ( string userName, string path )
        {
            int isPM = 0;

            try
            {
                Project project = WebServicesHelper.GetProject ( path );

                Guid siteCollectionId = default ( Guid );
                string serverRelativeUrl = default ( string );
                SPHelpers.GetSiteCollectionIdAndServerRelativeUrl ( path, out siteCollectionId, out serverRelativeUrl );

                User user = UserModel.GetUserByLogin ( userName, siteCollectionId, serverRelativeUrl );

                LoggingManager.LogMessage ( "Information",
                    string.Format ( "User was found for login: {0} -> {1} {2}", userName, user.FirstName, user.LastName ) );

                if ( user.IsAdministrator || user.ManageProjectsOnly )
                {
                    isPM = user.Id;
                }
                else if ( project != null && project.ProjectManagerIds != null && project.ProjectManagerIds.Count > 0 )
                {
                    if ( user != null && project.ProjectManagerIds.Contains ( user.Id ) )
                    {
                        isPM = user.Id;
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }

            LoggingManager.LogMessage ( "Information",
                string.Format ( "User login: {0} -> returning id: {1}", userName, isPM ) );

            return isPM;
        }

        internal bool IsProjectManager ( int userId, string path )
        {
            bool isPM = false;

            try
            {
                Guid siteCollectionId = default ( Guid );
                string serverRelativeUrl = default ( string );
                SPHelpers.GetSiteCollectionIdAndServerRelativeUrl ( path, out siteCollectionId, out serverRelativeUrl );

                User user = UserModel.GetUserById ( userId, siteCollectionId, serverRelativeUrl );
                isPM = user.IsAdministrator || user.ManageProjectsOnly;

                Project project = WebServicesHelper.GetProject ( path );
                if ( !isPM && project != null && project.ProjectManagerIds != null && project.ProjectManagerIds.Count > 0 )
                {
                    if ( userId > 0 && project.ProjectManagerIds.Contains ( userId ) )
                        isPM = true;
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }

            return isPM;
        }

        [WebMethod]
        public bool IsDirty ( string path, int userId, out bool firstSync )
        {
            firstSync = true;
            bool planDirty = false;

            try
            {
                Project project = WebServicesHelper.GetProject ( path );
                firstSync = !project.IsSynched;
                planDirty = project.PlanDirty;
            }
            catch ( Exception )
            {
            }

            return planDirty;
        }

        [WebMethod]
        public bool VersionCheck ( string path, int userId, string version )
        {
            bool versionOk = false;

            try
            {
                Project project = WebServicesHelper.GetProject ( path );
                Version currentVersion = new Version ( version );
                Version minimumVersion = new Version ( Constants.MSProjectPlugin.MinimumPluginVersion );
                if ( currentVersion >= minimumVersion )
                    versionOk = true;
            }
            catch ( Exception )
            {
            }

            return versionOk;
        }

        [WebMethod]
        public string MidoriToProject ( string path, string name, int userId )
        {
            bool isPM = false;
            bool IsValidProject = false;
            XmlDocument xmlMidori = new XmlDocument ( );
            xmlMidori.LoadXml ( "<Midori></Midori>" );

            try
            {
                #region Validate User

                isPM = IsProjectManager ( userId, path );
                if ( !isPM )
                    throw new Exception ( "User is not a valid Project Manager for this project." );

                #endregion

                #region Validate Project

                Project project = WebServicesHelper.GetProject ( path );
                string encodedPlanUrl = Server.UrlPathEncode ( project.ProjectPlanFileUrl );
                name = Server.UrlPathEncode ( name );
                IsValidProject = ( project != null && name.ToUpper ( ).EndsWith ( encodedPlanUrl.ToUpper ( ) ) && isPM );

                if ( IsValidProject && project != null && project.ProjectStatus == ProjectStatus.Closed )
                    throw new Exception ( "The Project has been closed in Kiiro" );

                #endregion

                if ( IsValidProject )
                {
                    Guid siteCollectionId = default ( Guid );
                    string portalServerRelativeUrl = default ( string );
                    string projectServerRelativeUrl = project.ServerRelativeWebUrl;
                    SPHelpers.GetSiteCollectionIdAndServerRelativeUrl ( path, out siteCollectionId, out portalServerRelativeUrl );

                    List<User> users = UserModel.GetActiveUsers ( siteCollectionId, portalServerRelativeUrl );
                    List<TeamMember> teamMembers = TeamModel.GetTeamMembers ( siteCollectionId, projectServerRelativeUrl );
                    List<Work> midoriTasks = WorkModel.GetAllTasks ( siteCollectionId, projectServerRelativeUrl );
                    Dictionary<int, string> projectUsers = WebServicesHelper.PopulateTeamDictionary ( teamMembers, users );

                    if ( midoriTasks != null )
                        WebServicesHelper.PopulateXmlTasks ( xmlMidori, midoriTasks, projectUsers, project );

                    WebServicesHelper.PopulateXmlProject ( xmlMidori, project );
                    WebServicesHelper.PopulateXmlTeam ( xmlMidori, projectUsers );
                }
                else
                    throw new Exception ( "Project Plan does not belong to a Midori Project" );
            }
            catch ( Exception ex )
            {
                throw ex;
            }

            return xmlMidori.InnerXml;
        }

        [WebMethod]
        public void ProjectToMidori ( XmlDocument xmlProject, XmlDocument xmlTasks, string path, string name, int userId )
        {
            bool isPM = false;
            bool isValidProject = false;
            Midori midori = new Midori ( );

            try
            {
                #region Validate User

                isPM = IsProjectManager ( userId, path );
                if ( !isPM )
                    throw new Exception ( "User is not a valid Project Manager for this project." );

                #endregion

                #region Validate Project

                Project project = WebServicesHelper.GetProject ( path );
                string encodedPlanUrl = Server.UrlPathEncode ( project.ProjectPlanFileUrl );
                name = Server.UrlPathEncode ( name );
                isValidProject = ( project != null && name.ToUpper ( ).EndsWith ( encodedPlanUrl.ToUpper ( ) ) && isPM );

                if ( isValidProject && project != null && project.ProjectStatus == ProjectStatus.Closed )
                    throw new Exception ( "The Project has been closed in Kiiro" );

                #endregion

                if ( isValidProject )
                {
                    Guid siteCollectionId = default ( Guid );
                    string portalServerRelativeUrl = default ( string );
                    string projectServerRelativeUrl = project.ServerRelativeWebUrl;
                    SPHelpers.GetSiteCollectionIdAndServerRelativeUrl ( path, out siteCollectionId, out portalServerRelativeUrl );

                    User user = UserModel.GetUserById ( userId, siteCollectionId, portalServerRelativeUrl );

                    #region Team Members

                    List<User> users = UserModel.GetActiveUsers ( siteCollectionId, portalServerRelativeUrl );
                    Dictionary<string, int> projectUsers = WebServicesHelper.PopulateTeamDictionary ( xmlProject, users );
                    List<TeamMember> teamMembers = TeamModel.GetTeamMembers ( siteCollectionId, projectServerRelativeUrl );

                    foreach ( int value in projectUsers.Values )
                    {
                        bool isOnTeam = false;
                        isOnTeam = teamMembers.Exists ( x => x.UserId == value );
                        if ( !isOnTeam )
                        {
                            TeamMember newMember = new TeamMember ( );
                            newMember.CreatedBy = user;
                            newMember.CreatedDate = DateTime.Now;
                            newMember.EditType = EditType.Created;
                            newMember.ModifiedBy = user;
                            newMember.ModifiedDate = DateTime.Now;
                            newMember.RoleOnProject = "Team Member";
                            newMember.UserId = value;
                            newMember.User = users.Find ( x => x.Id == value );
                            TeamModel.Save ( newMember, siteCollectionId, projectServerRelativeUrl );
                        }
                    }

                    #endregion

                    #region Update and Delete tasks

                    List<Work> midoriTasks = WorkModel.GetAllTasks ( siteCollectionId, projectServerRelativeUrl );
                    if ( midoriTasks == null )
                        midoriTasks = new List<Work> ( );

                    List<Work> fromTasks = new List<Work> ( );

                    foreach ( XmlNode xmlTask in xmlTasks.DocumentElement.ChildNodes )
                        fromTasks.Add ( WebServicesHelper.XmlToWork ( xmlTask, projectUsers ) );

                    foreach ( Work fromTask in fromTasks )
                    {
                        if ( fromTask.EditType == EditType.Updated )
                        {
                            Work work = null;
                            work = midoriTasks.Find ( x => ( x.PlanId == fromTask.PlanId || x.Id == fromTask.Id ) );
                            if ( work != null )
                            {
                                WebServicesHelper.PopulateWork ( work, fromTask );
                                work.ModifiedBy = user;
                                work.EditType = EditType.Updated;
                                work.ModifiedDate = DateTime.Now;
                                work.IsFromProjectPlan = true;
                                midori.Work.Add ( work );
                            }
                            else // If task was deleted in Kiiro, but updated in MS Project, create it as a new task.
                            {
                                work = new Work ( );
                                WebServicesHelper.PopulateWork ( work, fromTask );

                                work.CreatedBy = user;
                                work.CreatedDate = DateTime.Now;
                                work.ModifiedBy = user;
                                work.ModifiedDate = DateTime.Now;
                                work.ServerRelativeUrl = project.ServerRelativeWebUrl;
                                work.SiteCollectionId = project.SiteCollectionId;
                                work.IsFromProjectPlan = true;
                                work.EditType = EditType.Created;

                                midori.Work.Add ( work );
                            }
                        }
                        else if ( fromTask.EditType == EditType.Deleted )
                        {
                            Work work = null;
                            work = midoriTasks.Find ( x => ( x.PlanId == fromTask.PlanId || x.Id == fromTask.Id ) );
                            if ( work != null )
                            {
                                work.ModifiedBy = user;
                                work.EditType = EditType.Deleted;
                                midori.Work.Add ( work );                                
                            }
                        }
                        else if ( fromTask.EditType == EditType.Created )
                        {
                            Work work = new Work ( );
                            WebServicesHelper.PopulateWork ( work, fromTask );

                            work.CreatedBy = user;
                            work.CreatedDate = DateTime.Now;
                            work.ModifiedBy = user;
                            work.ModifiedDate = DateTime.Now;
                            work.ServerRelativeUrl = project.ServerRelativeWebUrl;
                            work.SiteCollectionId = project.SiteCollectionId;
                            work.IsFromProjectPlan = true;
                            work.EditType = EditType.Created;

                            midori.Work.Add ( work );
                        }
                    }

                    #endregion

                    #region Update Project

                    WebServicesHelper.PopulateProject ( project, xmlProject );

                    project.ModifiedBy = user;
                    project.ModifiedDate = DateTime.Now;
                    project.EditType = EditType.Updated;

                    midori.Projects.Add ( project );
                    WorkModel.Save ( midori, siteCollectionId, projectServerRelativeUrl );
                    ProjectsModel.ProjectIsSynched ( project, siteCollectionId, portalServerRelativeUrl );

                    #endregion

                }
                else
                    throw new Exception ( "Project Plan does not belong to a Midori Project" );

            }
            catch ( Exception ex )
            {
                throw ex;
            }
        }
    }
}

/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.WebServices/KiiroServices.asmx.cs $
 * 
 * 21    2/08/10 5:04p Camerons
 * 
 * 20    1/25/10 1:17p Camerons
 * 
 * 19    1/12/10 12:03p Camerons
 * 
 * 18    26/11/09 10:35a Camerons
 * 
 * 17    17/11/09 6:46p Camerons
 * 
 * 16    11/17/09 3:18p Stefanf
 * 
 * 15    8/11/09 2:16p Camerons
 * 
 * 14    10/02/09 10:46a Stefanf
 * 
 * 13    25/09/09 9:57a Camerons
 * 
 * 12    22/09/09 6:03p Camerons
 * Code changes to support creating user on demand - version 1.1.x.x
 * 
 * 11    21/09/09 3:30p Camerons
 * First batch of changes for 1.1.x.x - Security groups update
 * 
 * 10    11/09/09 3:40p Camerons
 * 
 * 9     8/31/09 3:36p Stefanf
 * 
 * 8     17/08/09 10:45a Camerons
 * Added check-in comments section
 * 
 ************************************************************************/